package com.demo.ping.service.impl

import com.demo.ping.service.PingService
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
import org.mockito.junit.jupiter.MockitoExtension
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
import reactor.test.StepVerifier

import static org.mockito.ArgumentMatchers.anyString
import static org.mockito.Mockito.when

@ExtendWith(MockitoExtension.class)
class PingServiceImplTest {

    @Mock
    private WebClient.Builder webClientBuilder

    @Mock
    private WebClient webClient

    @Mock
    private WebClient.RequestHeadersUriSpec requestHeadersUriSpec

    @Mock
    private WebClient.RequestHeadersSpec requestHeadersSpec

    @Mock
    private WebClient.ResponseSpec responseSpec

    private PingService pingService

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this)
        when(webClientBuilder.baseUrl(anyString())).thenReturn(webClientBuilder)
        when(webClientBuilder.build()).thenReturn(webClient)
        when(webClient.get()).thenReturn(requestHeadersUriSpec)
        when(requestHeadersUriSpec.uri(anyString())).thenReturn(requestHeadersSpec)
        when(requestHeadersSpec.retrieve()).thenReturn(responseSpec)
        pingService = new PingServiceImpl(webClientBuilder, "http://localhost:8080")
    }

    @Test
    void testSayHello_happyFlow() {
        // Arrange
        String expectedResponse = "world"
        when(responseSpec.bodyToMono(String.class)).thenReturn(Mono.just(expectedResponse))

        // Act
        Mono<String> result = pingService.sayHello()

        // Assert
        StepVerifier.create(result)
                .expectNext(expectedResponse)
                .verifyComplete()
    }

    @Test
    void testSayHello_Failure() {
        // Arrange
        when(responseSpec.bodyToMono(String.class)).thenThrow(new RuntimeException("Server not found"))

        // Act
        Mono<String> response = pingService.sayHello()

        // Assert
        StepVerifier.create(response)
                .expectErrorMatches({ throwable -> throwable instanceof RuntimeException && throwable.message == "Server not found" })
                .verify()
    }
}